package com.zuoshenge.sys.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.zuoshenge.sys.bean.JwtProperties;
import com.zuoshenge.sys.dto.UserInfoDto;
import com.zuoshenge.sys.entity.User;
import com.zuoshenge.sys.entity.UserRecord;
import com.zuoshenge.sys.expection.BadRequestException;
import com.zuoshenge.sys.service.MyUserDetailService;
import com.zuoshenge.sys.service.OnlineUserService;
import com.zuoshenge.sys.service.UserDataService;
import com.zuoshenge.sys.utils.JwtTokenUtil;
import com.zuoshenge.sys.utils.RedisUtil;
import com.zuoshenge.sys.dto.UserRequestDTO;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/auth")
public class AuthController {

    private static final String CAPTCHA_PREFIX = "captcha:";

    private static final String DEFAULT_USER_NICKNAME = "未设置昵称";

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private JwtProperties jwtProperties;

    @Resource
    private JwtTokenUtil jwtTokenUtil;

    @Resource
    private MyUserDetailService myUserDetailService;

    @Resource
    private UserDataService userDataService;

    @Resource
    private OnlineUserService onlineUserService;

    @Resource
    private PasswordEncoder passwordEncoder;

    @PostMapping(value = "/info")
    public ResponseEntity<Object> getUserInfo(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        User user = null;
        if (token != null && !token.isEmpty()) {
            token = token.substring(7);
            String username = (String)redisUtil.get(jwtTokenUtil.loginKey(token));
            user = userDataService.loadUserByUsername(username);
        }
        if (user == null) {
            throw new NullPointerException("用户为空！");
        }

        UserInfoDto userInfoDto = new UserInfoDto(
                user.getUsername(),
                user.getNickname(),
                user.getPoints(),
                user.getFreeCount(),
                user.getExtraCount()
        );
        Map<String, Object> authInfo = new HashMap<String, Object>(3) {{
            put("user", userInfoDto );
        }};
        return ResponseEntity.ok(authInfo);
    }

    @PostMapping("/register")
    public ResponseEntity<Object> register(@RequestBody UserRequestDTO userRequestDTO) {
        String code = (String) redisUtil.get(userRequestDTO.getUuid());
        redisUtil.del(userRequestDTO.getUuid());
        if (StringUtils.isBlank(code)) {
            throw new BadRequestException("验证码已过期，请重新获取！");
        }
        if (StringUtils.isBlank(userRequestDTO.getCode()) || !code.equalsIgnoreCase(userRequestDTO.getCode())) {
            throw new BadRequestException("验证码输入不正确！");
        }
        if (userDataService.loadUserByUsername(userRequestDTO.getUsername()) != null) {
            throw new BadRequestException("注册失败！该用户已经存在");
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
        sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 使用"Asia/Shanghai"更精确
        User user = new User(
                null,
                userRequestDTO.getUsername(),
                passwordEncoder.encode(userRequestDTO.getPassword()),
                DEFAULT_USER_NICKNAME,
                sdf.format(new Date()),
                0,
                0,
                100,
                0
        );

        userDataService.addUser(user);
        UserDetails userDetails = myUserDetailService.loadUserByUsername(user.getUsername());
        Authentication authentication = new UsernamePasswordAuthenticationToken(user, null, userDetails.getAuthorities());
        String jwt = jwtTokenUtil.generateToken(authentication);
        onlineUserService.save(user,jwt);
        Map<String, Object> authInfo = new HashMap<String, Object>(2) {{
            put("token", jwtProperties.getTokenStartWith() + jwt);
            put("user", user);
        }};

        return ResponseEntity.ok(authInfo);
    }

    @PostMapping("/login")
    public ResponseEntity<Object> login(@RequestBody UserRequestDTO userRequestDTO) {
        String code = (String) redisUtil.get(userRequestDTO.getUuid());
//        System.out.println("记住我：" + userInfoDTO.getRememberMe());
        redisUtil.del(userRequestDTO.getUuid());
        if (StringUtils.isBlank(code)) {
            throw new BadRequestException("验证码已过期，请重新获取！");
        }
        if (StringUtils.isBlank(userRequestDTO.getCode()) || !code.equalsIgnoreCase(userRequestDTO.getCode())) {
            throw new BadRequestException("验证码输入不正确！");
        }
        UserDetails userDetails = myUserDetailService.loadUserByUsername(userRequestDTO.getUsername());
        if (!passwordEncoder.matches(userRequestDTO.getPassword(), userDetails.getPassword())) {
            throw new BadRequestException("用户名或密码错误！");
        }
        Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, userRequestDTO.getPassword(), userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String jwt = jwtTokenUtil.generateToken(authentication);
        User user = userDataService.loadUserByUsername(userRequestDTO.getUsername());

        Map<String, Object> authInfo = new HashMap<String, Object>(3) {{
            put("token", jwtProperties.getTokenStartWith() + jwt);
            put("user", user);
        }};

        System.out.println("首次创建的token：" + jwtProperties.getTokenStartWith() + jwt);

        String onlineUsername = onlineUserService.queryOnlineUsername(user.getUsername());
        if (onlineUsername != null && !StringUtils.isBlank(onlineUsername)) {
            // 踢掉之前已经登录的token
            onlineUserService.kickOutForUsername(user.getUsername());
        }
        onlineUserService.save(user,jwt);
        // 配置记住我令牌
//        if (userInfoDTO.getRememberMe()) {
//            String rememberJwt = jwtTokenUtil.generateRememberMeToken(authentication);
//            authInfo.put("rememberToken", rememberJwt);
//            onlineUserService.saveForRememberMe(user, rememberJwt);
//        }
        return ResponseEntity.ok(authInfo);
    }

    @GetMapping("/get-code")
    public ResponseEntity<Object> getCaptcha(String captchaId) {
        // 创建一个图像验证码宽度为130，高度为48，包含4个字符，干扰线10个
        CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(130, 48, 4, 10);
        // 获取验证码的文本
        String captchaText = circleCaptcha.getCode();
        // 获取验证码图片的Base64编码
        String captchaImageBase64Data = circleCaptcha.getImageBase64Data();
        // 如果没有传入captchaId，则生成一个随机字符串作为captchaId
        String uuid = CAPTCHA_PREFIX + Optional.ofNullable(captchaId).orElseGet(() -> UUID.randomUUID().toString());
        // 保存验证码文本到Redis中，有效期30秒
        redisUtil.setNx(uuid, captchaText, 20L, TimeUnit.SECONDS);
        Map<String, Object> imgResult = new HashMap<String, Object>(2) {{
            put("img", captchaImageBase64Data);
            put("uuid", uuid);
        }};
        return ResponseEntity.ok(imgResult);
    }

    @DeleteMapping("/logout")
    public ResponseEntity<Object> logout(HttpServletRequest request) {
        String token = jwtTokenUtil.getToken(request);
        onlineUserService.logout(token);
        return new ResponseEntity<>(HttpStatus.OK);
    }

    @PostMapping("/test")
    public void test() {
        System.out.println(System.currentTimeMillis());
        System.out.println("test");
    }
}

